<?php
/**
 * Created by PhpStorm.
 * User: hb
 * Date: 18-4-3
 * Time: 下午2:12
 */

namespace app\Controllers;

use Server\CoreBase\ChildProxy;

use WsdServer\CoreBase\JsonRpcController;

use WsdServer\Lib\Facade\Cache;
use WsdServer\Lib\Facade\Config;
use WsdServer\Lib\Facade\DB;
use WsdServer\Lib\Facade\Redis;
use WsdServer\Lib\Facade\Request;
use WsdServer\Lib\McQueue;
use WsdServer\Lib\Session\PhpSessionHandler;
use WsdServer\Lib\Session\PhpSessionManager;

use app\Logger\WsdLogger;

use App\Exceptions\OmgException;

use App\Models\Activity;
use App\Models\SignInSystem;
use App\Models\UserAttribute;

use App\Service\ActivityService;
use App\Service\Attributes;
use App\Service\Func;
use App\Service\SendAward;
use App\Service\SendMessage;
use App\Service\SignInSystemBasic;

class rpc extends JsonRpcController
{
    protected $laravel_cm;

    //private $phpSession;
    private $swooleSession;
    private $user_id;

    private $execStartTime;     // 请求处理开始时间

    public $logger;             // 日志记录

    public function __construct($proxy = ChildProxy::class)
    {
        parent::__construct($proxy);

        $this->logger = new WsdLogger('OmgApi', 'omg_api');
    }

    /**
     * 初始化每次执行方法之前都会执行initialization
     * @param string $controller_name 准备执行的controller名称
     * @param string $method_name 准备执行的method名称
     * @throws \Exception
     */
    protected function initialization($controller_name, $method_name)
    {
        $this->execStartTime = microtime(true);     // 记录请求处理开始时间

        parent::initialization($controller_name, $method_name);

        // TODO by hb on 2018-04-19: 需检查x-real-ip及x-forwarded-for是可信任而非伪造的。
        $_REQUEST['client_ip'] = $this->http_input->getRequestHeader('x-real-ip');
        if ( empty($_REQUEST['client_ip']) ){
            $xForwardFor = $this->http_input->getRequestHeader('x-forwarded-for');
            if ( !empty($xForwardFor) ){
                //preg_match_all('{("?\[?)([a-z0-9\.:_\-/]*)}', $xForwardFor, $matches);
                $matches = explode(",", trim($xForwardFor));
                $_REQUEST['client_ip'] = trim($matches[0]);
            }
        }
        if ( empty($_REQUEST['client_ip']) && !empty($this->request->server['remote_addr']) ) {
            $_REQUEST['client_ip'] = $this->request->server['remote_addr'];
        }
        $_REQUEST['user_agent'] = $this->http_input->getRequestHeader('user-agent');

        /*
        // 方式1：PhpSession，不推荐
        ini_set("session.save_handler", Config::get('rpcsession.handler'));
        ini_set("session.save_path", Config::get('rpcsession.path'));
        ini_set("session.name", Config::get('rpcsession.name'));
        ini_set("session.cookie_domain", Config::get('rpcsession.domain'));
        $_COOKIE = $this->request->cookie;
        $this->phpSession = new PhpSessionHandler();
        $this->phpSession->setGroup(env('ACCOUNT_BASE_HOST'));
        //secho("rpc::swooleCookie", $this->phpSession->id);
        $this->user_id = $this->phpSession->get('userData.user_id');
        */

        // 方式2：SwooleSession
        $session_name = Config::get('rpcsession.name');
        $swooleCookie = $this->request->cookie[$session_name];
        //secho(__CLASS__.':'.__LINE__, "swooleCookie=[{$swooleCookie}]");
        $this->swooleSession = (new PhpSessionManager($this))->driver();
        $this->swooleSession->setId($swooleCookie);
        //$this->swooleSession->setGroup('php1.wanglibao.com');
        $this->swooleSession->setGroup(env('ACCOUNT_BASE_HOST'));
        $this->swooleSession->start();
        $this->user_id = $this->swooleSession->get('userData.user_id');
        //secho(__CLASS__.':'.__LINE__, "user_id=[{$this->user_id}]");

        //$this->user_id = 1716707;
        global $userId;
        $userId = $this->user_id;
    }

    /*private function getAwardList_Miner() {
        // 使用SD自带Miner
        //if($this->laravel_cm->has('sign_in_system_list')){
        if(Cache::has('sign_in_system_list')){
            return $this->laravel_cm->get('sign_in_system_list');
        }
        $result = yield $this->mysql_pool->dbQueryBuilder
            ->select('user_id, award_name')->from('sign_in_system')
            ->orderBy('id', 'desc')->limit(20)
            ->coroutineSend();
        //var_dump($result);
        $data = $result['result'];
        foreach ($data as &$item){
            if(!empty($item) && isset($item['user_id']) && !empty($item['user_id'])){
                //$phone = Func::getUserPhone($item['user_id']);
                $phone = "13912345678";
                $item['phone'] = !empty($phone) ? substr_replace($phone, '******', 3, 6) : "";
            }
        }
        Cache::put('sign_in_system_list', $data, 2);
        return $data;
    }*/

    public function __batchRPC($params) {
        $resp = [];
        foreach($params as $item) {
            if ( isset($item['jsonrpc']) && $item['jsonrpc']=='2.0' ) {
                try {
                    $rpcId = (int) $item['id'];
                    $func = $item['method'].'Action';
                    $params = $item['params'];
                    if ($params == null) {
                        $result = yield call_user_func([$this, $func]);
                    } else {
                        $result = yield call_user_func_array([$this, $func], $params);
                    }
                    $resp[] = [
                        "id" => $rpcId,
                        "jsonrpc" => "2.0",
                        "result" => $result
                    ];
                } catch (\Exception $ex) {
                    $resp[] = [
                        "id" => $rpcId,
                        "jsonrpc" => "2.0",
                        "error" => [ "code"=>$ex->getCode(), "message"=>$ex->getMessage() ]
                    ];
                }
            }
        }
        $this->http_output->setContentType('application/json');
        $this->http_output->end(json_encode($resp));

        $log_data = Array(
            "IPADDR" => Request::getClientIp(),
            "EXEC" => sprintf('%.2fms', (microtime(true) - $this->execStartTime)*1000)
        );
        $this->logger->info("__batchRPC", $log_data);
    }

    public function signInSystemInfo()
    {
        try {
            $result = $this->signInSystemInfoAction();
            $resp = [
                "id" => (int) $this->rpc_request_id,
                "jsonrpc" => "2.0",
                "result" => $result
            ];
            $this->http_output->setContentType('application/json');
            $this->http_output->end(json_encode($resp));
        } catch (\Exception $ex) {
            $this->returnException($ex);
        }

        $log_data = Array(
            "IPADDR" => Request::getClientIp(),
            "EXEC" => sprintf('%.2fms', (microtime(true) - $this->execStartTime)*1000)
        );
        $this->logger->info("signInSystemInfo", $log_data);
    }

    public function signInSystemDraw()
    {
        try {
            $result = $this->signInSystemDrawAction();
            $resp = [
                "id" => (int) $this->rpc_request_id,
                "jsonrpc" => "2.0",
                "result" => $result
            ];
            $this->http_output->setContentType('application/json');
            $this->http_output->end(json_encode($resp));
        } catch (\Exception $ex) {
            $this->returnException($ex);
        }
        $log_data = Array(
            "IPADDR" => Request::getClientIp(),
            "EXEC" => sprintf('%.2fms', (microtime(true) - $this->execStartTime)*1000)
        );
        $this->logger->info("signInSystemDraw", $log_data);
    }

    public function signin()
    {
        try {
            $result = $this->signinAction();
            $resp = [
                "id" => (int) $this->rpc_request_id,
                "jsonrpc" => "2.0",
                "result" => $result
            ];
            $this->http_output->setContentType('application/json');
            $this->http_output->end(json_encode($resp));
        } catch (\Exception $ex) {
            $this->returnException($ex);
        }
        $log_data = Array(
            "IPADDR" => Request::getClientIp(),
            "EXEC" => sprintf('%.2fms', (microtime(true) - $this->execStartTime)*1000)
        );
        $this->logger->info("signin", $log_data);
    }

    public function signinWechat($params)
    {
        try {
            $params = isset($params[0]) && !empty($params[0]) ? $params[0] : [];
            $user_id = isset($params['userId']) ? $params['userId'] : 0;
            if($user_id <= 0){
                throw new OmgException(OmgException::API_MIS_PARAMS);
            }
            $ipList = explode(",",env("INTERNAL_IPS"));
            $reqIP = Request::getClientIp();
            $res = array_search($reqIP, $ipList);
            if($res === false) {
                throw new OmgException(OmgException::API_ILLEGAL);
            }
            $result = $this->innerSignin($user_id);
            $resp = [
                "id" => (int) $this->rpc_request_id,
                "jsonrpc" => "2.0",
                "result" => $result
            ];
            $this->http_output->setContentType('application/json');
            $this->http_output->end(json_encode($resp));
        } catch (\Exception $ex) {
            $this->returnException($ex);
        }
        $log_data = Array(
            "UserId" => $user_id,
            "IPADDR" => Request::getClientIp(),
            "EXEC" => sprintf('%.2fms', (microtime(true) - $this->execStartTime)*1000)
        );
        $this->logger->info("signinWechat", $log_data);
    }
    public function signinDay($params)
    {
        try {
            $params = isset($params[0]) && !empty($params[0]) ? $params[0] : [];
            $result = $this->signinDayAction($params);
            $resp = [
                "id" => (int) $this->rpc_request_id,
                "jsonrpc" => "2.0",
                "result" => $result
            ];
            $this->http_output->setContentType('application/json');
            $this->http_output->end(json_encode($resp));
        } catch (\Exception $ex) {
            $this->returnException($ex);
        }
        $log_data = Array(
            "IPADDR" => Request::getClientIp(),
            "EXEC" => sprintf('%.2fms', (microtime(true) - $this->execStartTime)*1000)
        );
        $this->logger->info("signinDay", $log_data);
    }
    /************************************************************/


    /**
     * 查询当前状态
     *
     * @JsonRpcMethod
     */
    public function signInSystemInfoAction() {
        global $userId;
        //$userId = 1716707;
        $config = Config::get('signinsystem');
        $user = ['invested' => false, 'login' => false, 'multiple' => 1, 'multiple_card' => 0,'user_end_time' => 0];
        $game = ['available' => false, 'awardNum' => 0, 'nextSeconds' => 0];
        $awardList = $this->getAwardList();

        // 用户是否登录
        if(!empty($userId)) {
            $user['login'] = true;
        }

        // 用户是否投资过
        if($user['login']) {
            $user['invested'] = $this->isInvested($userId, $config);
        }

        // 获取用户倍数signInSystemInfo
        if($user['login']) {
            $user['multiple'] = $this->getMultiple($userId, $config);
            //获取加倍卡
            $multipleCard = $this->signInEveryDayMultipleCache($userId);
            if($multipleCard > 0){
                $user['multiple_card'] = $multipleCard;
            }
            //获取用户摇一摇结束时间
            $userAtt = UserAttribute::where(['user_id'=> $userId,'key' => $config['trade_alias_name']])->first();
            $times = isset($userAtt->number) ? $userAtt->number - time() : 0;
            $user['user_end_time'] = $times <= 0 ? 0 : $times;
        }

        // 活动是否存在
        if($this->activityIsEnd($config['alias_name'])) {
            $game['available'] = true;
        }


        // 下次活动开始时间
        if($game['available']) {
            $item = $this->selectList($config['lists']);
            $game['awardNum'] = $this->getLastGlobalNum($item);
            $game['nextSeconds'] = $item['endTimestamps'] - time() + rand(0,3);
        }


        return [
            'code' => 0,
            'message' => 'success',
            'data' => [
                'game' => $game,
                'user' => $user,
                'awardList' => $awardList
            ],
        ];
    }

    /**
     * 抽奖
     *
     * @JsonRpcMethod
     */
    public function signInSystemDrawAction() {
        global $userId;
        //$userId = 1716707;
        if(!$userId){
            throw new OmgException(OmgException::NO_LOGIN);
        }

        $config = Config::get('signinsystem');

        if(!$this->isInvested($userId, $config)) {
            throw new OmgException(OmgException::CONDITION_NOT_ENOUGH);
        }

        // 是否触发间隔限制
        if($this->isTooOften($userId, $config)) {
            throw new OmgException(OmgException::API_BUSY);
        }

        $result = [
            'awardName' => '',
            'awardType' => 0,
            'amount' => 0,
            'multiple' => 1,
            'multiple_card' => 0,
            'lastGlobalNum' => 0
        ];

        // 活动是否存在
        if(!$this->activityIsEnd($config['alias_name'])) {
            throw new OmgException(OmgException::ACTIVITY_NOT_EXIST);
        }

        $item = $this->selectList($config['lists']);

        // 奖品是否还有
        $lastGlobalNum = $this->getLastGlobalNum($item);
        if(!$lastGlobalNum) {
            throw new OmgException(OmgException::NUMBER_IS_NULL);
        }

        $result['lastGlobalNum'] = $lastGlobalNum - 1;
        // 获取奖品
        $award = $this->getAward($item);

        //获取倍数
        $result['multiple'] = $this->getMultiple($userId, $config);
        //获取加倍卡
        $multipleCard = $this->signInEveryDayMultipleCache($userId);
        if($multipleCard > 0){
            $result['multiple_card'] = $multipleCard;
        }

        // 创建记录
        $result['awardName'] = $award['is_rmb'] ? $award['size'] . '元' : "100元摇一摇红包";
        $result['amount'] = $award['is_rmb'] ? strval($award['size']) : 100;
        $result['awardType'] = $award['is_rmb'] ? 7 : 2;
        $uuid = SendAward::create_guid();
        /***********************异步**************************
        $res = SignInSystem::create([
            'user_id' => $userId,
            'award_name' => $result['awardName'],
            'uuid' => $uuid,
            'ip' => Request::getClientIp(),
            'amount' => $award['size'],
            'multiple' => $result['multiple'],
            'multiple_card' => $multipleCard,
            'user_agent' => Request::header('User-Agent'),
            'status' => 1,//默认是成功
            'type' => $result['awardType']
        ]);
        $amount = bcmul($award['size'], $result['multiple'] + $multipleCard, 2);

        //放到redis
        if($award['is_rmb']){
            $redisData = [
                'send_type'=> 7,//发送类型7是现金2是红包
                'user_id'=> $userId,//用户id
                'record_id'=> $res->id,//记录id
                'uuid'=> $uuid,//唯一ID
                'amount'=> $amount,//现金金额金额
                'type'=> "shake",//现金类型（摇一摇现金奖励）
                'sign' => hash('sha256', $userId.env('INSIDE_SECRET')),
            ];
        }else{
            $redisData = [
                'send_type'=>2,//发送类型7是现金2是红包
                'user_id' => $userId,
                'uuid' => $uuid,
                'source_id' => 0,
                'project_ids' =>'',
                'project_type' => 0,
                'project_duration_type' => 3,
                'project_duration_time' => 6,
                'name' => "100元摇一摇红包",
                'type' => 1,
                'amount' => 100,
                'effective_start' => date("Y-m-d H:i:s"),
                'effective_end' => date("Y-m-d H:i:s", strtotime("+7 days")),
                'investment_threshold' => 10000,
                'source_name' => "签到摇一摇",
                'platform' => 0,
                'limit_desc' => "10000元起投，限6月及以上标",
                'remark' => '',
            ];
            $message = ["sourcename"=>"签到摇一摇","awardname"=>"100元摇一摇红包"];
            SendMessage::Mail($userId,"恭喜您在'{{sourcename}}'活动中获得'{{awardname}}'奖励。",$message);
        }
        //放到队列
        Redis::LPUSH("shakeSendRewardList",json_encode($redisData));
        */
        //***********************同步START**************************
        $remark = [];
        // 发送现金
        if($award['is_rmb']) {
            // 创建记录
            $result['awardName'] = $award['size'] . '元';
            $result['amount'] = strval($award['size']);
            $result['awardType'] = 7;
            $res = SignInSystem::create([
                'user_id' => $userId,
                'award_name' => $result['awardName'],
                'uuid' => $uuid,
                'ip' => Request::getClientIp(),
                'amount' => $award['size'],
                'multiple' => $result['multiple'],
                'multiple_card' => $multipleCard,
                'user_agent' => Request::header('User-Agent'),
                'status' => 1,
                'type' => 7,
                'remark' => json_encode($remark, JSON_UNESCAPED_UNICODE),
            ]);

            $amount = bcmul($award['size'], $result['multiple'] + $multipleCard, 2);
            $purchaseRes = Func::incrementAvailable($userId, $res->id, $uuid, $amount, 'shake');
            
            // 失败
            if(!isset($purchaseRes['result'])) {
                $remark['addMoneyRes'] = $result;
                $remark['addMoneyReQ'] = $purchaseRes;
                $res->update(['status' => 0, 'remark' => json_encode($remark, JSON_UNESCAPED_UNICODE)]);
                throw new OmgException(OmgException::API_FAILED);
            }
        }

        // 根据别名发活动奖品
        if(!$award['is_rmb']) {
            $awards = SendAward::ActiveSendAward($userId, $award['alias_name']);
            if(isset($awards[0]['award_name']) && $awards[0]['status']) {
                $result['awardName'] = $awards[0]['award_name'];
                $result['awardType'] = $awards[0]['award_type'];
                $result['amount'] = strval(intval($result['awardName']));
                $remark['awards'] = $awards;
                SignInSystem::create([
                    'user_id' => $userId,
                    'amount' => $award['size'],
                    'award_name' => $result['awardName'],
                    'uuid' => '',
                    'ip' => Request::getClientIp(),
                    'user_agent' => Request::header('User-Agent'),
                    'status' => 1,
                    'type' => $result['awardType'],
                    'remark' => json_encode($remark, JSON_UNESCAPED_UNICODE),
                ]);
            }else{
                throw new OmgException(OmgException::API_FAILED);
            }
        }
        //***********************同步END**************************
        return [
            'code' => 0,
            'message' => 'success',
            'data' => $result
        ];
    }

    /**
     * 获取剩余奖品数量
     * @param $item
     * @return float|int
     */
    private function getLastGlobalNum($item) {
        // 活动开始一段时间后强制结束
        if(time() - $item['startTimestamps'] > $item['times']) {
            return 0;
        }

        $globalKey = Config::get('signinsystem.alias_name') . '_' . date('Ymd') . '_'. $item['start'];
        $awardNumberMultiple = Config::get('signinsystem.award_number_multiple');
        $usedGlobalNumber = Cache::get($globalKey, 0);
        $globalNumber = floor($this->getTotalNum($item) * $awardNumberMultiple);
        $lastGlobalNumber = $globalNumber - $usedGlobalNumber < 0  ? 0 :$globalNumber - $usedGlobalNumber;
        return $lastGlobalNumber;
    }

    /**
     * 获取奖品总数
     *
     * @param $item
     * @return int
     */
    private function getTotalNum($item) {
        $number = 0;
        foreach($item['awards'] as $award) {
            $number += $award['num'];
        }
        return $number;
    }

    /**
     * 获取奖品
     *
     * @param $item
     * @return mixed
     * @throws OmgException
     */
    private function getAward($item) {
        $number = $this->getTotalNum($item);

        $target = rand(1, $number);
        foreach($item['awards'] as $award) {
            $target = $target - $award['num'];
            if($target <= 0) {
                $globalKey = Config::get('signinsystem.alias_name') . '_' . date('Ymd') . '_'. $item['start'];
                Cache::increment($globalKey, 1);
                return $award;
            }
        }

        throw new OmgException(OmgException::NUMBER_IS_NULL);
    }

    /**
     * 获取倍率
     *
     * @param $userId
     * @param $config
     * @return int
     */
    private function getMultiple($userId, $config) {
        return Cache::remember("sign_in_system_multiple_{$userId}", 1, function() use ($userId, $config) {
            $inviteNum = Attributes::getNumber($userId, $config['invite_alias_name'], 0);
            foreach ($config['multipleLists'] as $item) {
                if ($inviteNum >= $item['min'] && $inviteNum <= $item['max']) {
                    return $item['multiple'];
                }
            }
            return 1;
        });
    }


    /**
     * 选择奖品
     *
     * @param $lists
     * @return mixed
     * @throws OmgException
     */
    private function selectList($lists) {
        foreach($lists as $item) {
            $startTimestamps = strtotime(date("Y-m-d {$item['start']}:00:00"));
            $endTimestamps = strtotime(date("Y-m-d {$item['end']}:00:00"));
            $now = time();
            if($item['start'] > $item['end']) {
                if($now < $endTimestamps){
                    $startTimestamps -= 3600*24;
                }else {
                    $endTimestamps += 3600*24;
                }
            }

            if($startTimestamps < $now && $now < $endTimestamps) {
                $item['startTimestamps'] = $startTimestamps;
                $item['endTimestamps'] = $endTimestamps;
                return $item;
            }
        }
        throw new OmgException(OmgException::ACTIVITY_NOT_EXIST);
    }

    /**
     * 获取获奖列表
     *
     * @return array
     */
    private function getAwardList() {
        return Cache::remember('sign_in_system_list', 2, function() {
            $data = SignInSystem::select('user_id', 'award_name')->orderBy('id', 'desc')->take(20)->get();
            foreach ($data as &$item){
                if(!empty($item) && isset($item['user_id']) && !empty($item['user_id'])){
                    $phone = Func::getUserPhone($item['user_id']);
                    //$phone = "13911219539";
                    $item['phone'] = !empty($phone) ? substr_replace($phone, '******', 3, 6) : "";
                }
            }
            return $data;
        });
    }

    /**
     * 抽奖间隔验证
     *
     * @param $userId
     * @param $config
     * @return bool
     */
    private function isTooOften($userId, $config) {
        $key = "sign_in_system_interval_{$userId}";
        if(Cache::has($key)){
            return true;
        }
        Cache::put($key, time(), $config['interval']/60);
        return false;
//        $value = Cache::pull($key);
//        Cache::put($key, time(), 10);
//        if($value && time()-$value < $config['interval']) {
//            return true;
//        }
//        return false;
    }

    /**
     * 用户投资标是否超过48小时
     *
     */
    private function isInvested($userId, $config) {
        $expired = Attributes::getNumber($userId, $config['trade_alias_name'], 0);
        if(time() < $expired) {
            return true;
        }
        return false;
    }

    /**
     * 活动是否存在加缓存
     */
    private function activityIsEnd($alias_name){
        $cacheKey = "activity_is_end".$alias_name;
        if(!Cache::has($cacheKey)){
            $status = ActivityService::isExistByAlias($alias_name);
            if($status){
                Cache::put($cacheKey,$status,5);
            }
            return $status;
        }
        return Cache::get($cacheKey);
    }
    /**
     * 获取加倍卡加缓存
     */
    private function signInEveryDayMultipleCache($userId){
        $cacheKey = "sign_in_every_day_multiple".$userId;
        if(!Cache::has($cacheKey)){
            $num = SignInSystemBasic::signInEveryDayMultiple($userId);
            if($num > 0){
                Cache::put($cacheKey,$num,5);
            }
            return $num;
        }
        return Cache::get($cacheKey);
    }

    /******************************************************************/

    /**
     * 签到
     *
     * @JsonRpcMethod
     */
    public function signinAction() {
        global $userId;
        if(!$userId) {
            throw new OmgException(OmgException::NO_LOGIN);
        }
        return $this->innerSignin($userId);
    }

    // 内部签到
    public function innerSignin($userId) {
        $aliasName = 'signin';
        $days = array(7, 14, 21, 28); //额外奖励
        $last = $days[count($days)-1]; //最后的天数
        $isSignIn = false; //是否签到过
        $continue = 1; //连续签到天数
        $award = [
            'name' => '',
            'type' => 0,
        ];

        //事务开始
        try {
            DB::beginTransaction();
            // Modify by hb on 2018-04-17
            //$activity = Activity::where('alias_name', $aliasName)->with('rules')->with('awards')->lockForUpdate()->first();
            $activity = Activity::where('alias_name', $aliasName)->with('rules')->with('awards')->first();
            if(!$activity) {
                throw new OmgException(OmgException::ACTIVITY_NOT_EXIST);
            }
            $signIn = Attributes::getItemLock($userId, $aliasName);

            //签到过
            if($signIn) {
                $lastUpdate = $signIn['updated_at'] ? $signIn['updated_at'] : $signIn['created_at'];
                $lastUpdateDate = date('Y-m-d', strtotime($lastUpdate));

                // 今天已签到
                if($lastUpdateDate == date('Y-m-d', time())) {
                    $isSignIn = true;
                    $continue = $signIn['number'] ?  $signIn['number'] : 0;
                    $award['name'] = $signIn['string'];
                }

                // 昨天已签到
                if($lastUpdateDate == date('Y-m-d', time() - 3600*24)) {
                    $award = $this->signSendAward($userId);
                    $continue = Attributes::increment($userId, $aliasName, 1, $award['name'], json_encode($award));
                }
            }

            //未签到或非连续签到
            if(empty($award['name'])) {
                $continue = 1;
                $award = $this->signSendAward($userId);
                Attributes::setItem($userId, $aliasName, $continue, $award['name'], json_encode($award));
            }

            // 送积分 & 发消息
            if(!$isSignIn) {
                if($continue >=7 )  {
                    SendAward::ActiveSendAward($userId, 'signin_point7'); // 连续签到7天送2积分
                } else {
                    SendAward::ActiveSendAward($userId, 'signin_point'); // 签到送1积分
                }
                $mcQueue = new McQueue();
                $mcQueue->put('daylySignin', array('user_id' => $userId, 'days' => $continue));
            }

            // 额外奖励进度
            $current = $continue%$last == 0 ? $last : $continue%$last;
            foreach($days as $key => $day) {
                if($current <= $day){
                    if($key == 0) {
                        $start = 1;
                    }else{
                        $start = $days[$key-1] + 1;
                    }
                    $end = $day;
                    break;
                }
            }

            // 是否领取额外奖励
            $extra = $this->isExtraAwards($userId, $end);
            // 是否分享
            $shared = $this->isShared($userId);
            DB::commit();

            return array(
                'code' => 0,
                'message' => 'success',
                'data' => array(
                    'isSignin' => $isSignIn,
                    'current' => $current,
                    'start' => $start,
                    'end' => $end,
                    'extra' => $extra,
                    'shared' => $shared,
                    'award' => [$award['name']],
                    'type' => $award['type'],
                    'last' => $last,
                ),
            );

        } catch (\Exception $ex) {
            DB::rollBack();
            $arr_ex = array( "user_id"=>$userId, "code"=>$ex->getCode(), "message"=>$ex->getMessage() );
            $this->logger->info("innerSignin", $arr_ex);
            throw $ex;
        }

    }

    //签到发奖
    private function signSendAward($userId) {
        $aliasName = 'signin';
        $interval = strtotime(date('Y-m-d 20:00:00')) - time();
        $rand = rand(1, 2);

        $award = [
            'name' => '谢谢参与',
            'type' => 0,
        ];
        if($interval < 0 || $rand === 1) {
            $awards = SendAward::ActiveSendAward($userId, $aliasName);
            if(!isset($awards[0]['award_name'])) {
                throw new OmgException(OmgException::ACTIVITY_NOT_EXIST);
            }
            $award['name'] = $awards[0]['award_name'];
            $award['type'] = $awards[0]['award_type'];
            return $award;
        }

        $multiple = rand(1,2)/10;
        SignInSystemBasic::signInEveryDayMultiple($userId, $multiple);
        $award['name'] = "${multiple}倍摇一摇翻倍特权";
        $award['type'] = 8;
        return $award;
    }

    // 获取额外奖励领取记录
    private function isExtraAwards($userId, $end) {
        $aliasName = "signinDay_{$end}";
        $extra = Attributes::getItem($userId, $aliasName);

        $lastUpdate = $extra['updated_at'] ? $extra['updated_at'] : $extra['created_at'];
        $lastUpdateDate = date('Y-m-d', strtotime($lastUpdate));

        // 今天领奖了
        if($lastUpdateDate == date('Y-m-d', time())) {
            return true;
        }

        return false;
    }

    // 今天是否分享
    private function isShared($userId) {
        $sharedName = 'signinShared';

        $shared = Attributes::getItem($userId, $sharedName);
        // 未分享记录
        if(!$shared) {
            return false;
        }

        //已分享
        $sharedUpdate = $shared['updated_at'] ? $shared['updated_at'] : $shared['created_at'];
        $sharedUpdateDate = date('Y-m-d', strtotime($sharedUpdate));
        if($sharedUpdateDate == date('Y-m-d', time())) {
            return true;
        }

        return false;
    }
    /**
     * 领取连续签到奖励signinDayAction
     *
     * @JsonRpcMethod
     */
    public function signinDayAction ($params) {
        global $userId;
        if(!$userId) {
            throw new OmgException(OmgException::NO_LOGIN);
        }
        $day = $params['day'];
        if($day <= 0){
            throw new OmgException(OmgException::PARAMS_ERROR);
        }
        $aliasName = "signinDay_{$day}";
        $signInName = 'signin';
        $isAward = false;
        $awardName = '';

        try {
            //事务开始
            DB::beginTransaction();
            $signIn = Attributes::getItemLock($userId, $signInName);
            if(!$signIn) {
                throw new OmgException(OmgException::NOT_SIGNIN);
            }
            $lastUpdate = $signIn['updated_at'] ? $signIn['updated_at'] : $signIn['created_at'];
            $lastUpdateDate = date('Y-m-d', strtotime($lastUpdate));
            if($lastUpdateDate !== date('Y-m-d', time())) {
                throw new OmgException(OmgException::NOT_SIGNIN);
            }

            $signInNum = $signIn['number'];
            $signInNum = $signInNum%28 == 0  ? 28 : $signInNum%28;

            if($signInNum !== $day) {
                throw new OmgException(OmgException::PARAMS_ERROR);
            }
            $extra = Attributes::getItemLock($userId, $aliasName);
            if($extra) {
                $extraLastUpdate = $extra['updated_at'] ? $extra['updated_at'] : $extra['created_at'];
                $extraLastUpdateDate = date('Y-m-d', strtotime($extraLastUpdate));
                if($extraLastUpdateDate == date('Y-m-d', time())) {
                    $isAward = true;
                    $awardName = $extra['string'];
                    $awardType = 0;
                }
            }

            if(!$isAward) {
                $awards = SendAward::ActiveSendAward($userId, $aliasName);
                $awardName = $awards[0]['award_name'];
                $awardType = $awards[0]['award_type'];
                Attributes::setItem($userId, $aliasName, time(), $awardName, json_encode($awards));
            }
            DB::commit();

            return array(
                'code' => 0,
                'message' => 'success',
                'data' => array(
                    'isAward' => $isAward,
                    'awards' => [$awardName],
                    'type' => $awardType,
                ),
            );
        } catch (\Exception $ex) {
            DB::rollBack();
            $arr_ex = array( "user_id"=>$userId, "code"=>$ex->getCode(), "message"=>$ex->getMessage() );
            $this->logger->info("signinDayAction", $arr_ex);
            throw $ex;
        }

    }

}